﻿using System;
using System.Data;
using System.Threading;
using MuZa.DBConnector;

namespace MuZa.MuZa
{
    internal class AgentP
    {
        private readonly Random _randNum;

        //public int Id { get; set; }

        public string Name { get; set; }

        private State State;

        //public string Location { get; set; }

        //int MyRandomNumber = RandNum.Next(1986, 2005);
        public AgentP()
        {
            this._randNum = new Random();
        }

        public AgentP(string name)
        {
            Name = name;
            State = new State();
            State.Free = true;
            this._randNum = new Random();
        }

        public AgentP(string name, State tState)
        {
            Name = name;
            State = tState;
            this._randNum = new Random();
        }

        public void Run()
        {
            while (true)
            {
                if (State.Free)
                //if (true)
                {
                    lock (this)
                    {
                        State.Free = false;

                        Console.WriteLine("Entering " + this.Name);

                        CheckRequestMesssge();
                        //CheckBookingStatus();
                        //Steps:
                        //    checked for requests
                        //    check for booking updates

                        Console.WriteLine("Exiting " + this.Name);

                        State.Free = true;
                        //Thread.Sleep(_randNum.Next(1000, 5000));
                        Thread.Sleep(5000);
                    }
                }
                else
                {
                    Thread.Sleep(10);
                }
            }
        }

        private void CheckRequestMesssge()
        {
            DataTable dTable = new DataTable();
            dTable = GetData.GetMessagesForParticipant(Name);

            for (int i = 0; i < dTable.Rows.Count; i++)
            {
                // an unread request messege
                string resName = dTable.Rows[i][2].ToString();
                string resType = dTable.Rows[i][7].ToString();
                string resStart = dTable.Rows[i][9].ToString();
                string resEnd = dTable.Rows[i][10].ToString();

                int requestedResourceQuantity = Convert.ToInt32(dTable.Rows[i][3]);
                int currentResourceQuantity = GetCurrentQuantityOfResource(resName, resType, resStart, resEnd);

                //msgStatus in unread
                if (Convert.ToInt32(dTable.Rows[i][4]) == MessageStatus.UnreadMessage)
                {
                    // Send Inf board NoR update
                    InfoBoard.IncrementNoRbyParticipant(Name);
                    GetData.WriteLog(this.Name, "Information Board", "Update", "NoR", "phase_3", this.Name + "updates NoR to IB");

                    // Check for the Request and Quantity
                    // If Avaiable
                    if (currentResourceQuantity >= requestedResourceQuantity)
                    {
                        // Upadte message status as 2 with deadline (not yet implemented)
                        int dt = GetData.sw.Elapsed.Seconds;
                        //dt = dt.AddSeconds(_randNum.Next(5, 10));
                        // add 30 seconds to the deadline
                        dt = dt + 30;

                        // Update quantity in IB
                        // Update his own quantity
                        UpdateResourceQuantity(resName, resType, -requestedResourceQuantity, resStart, resEnd);
                        //BookResource(resName, resType, requestedResourceQuantity, resStart, resEnd);
                        UpdateMessageStatus(Convert.ToInt32(dTable.Rows[i][5]), MessageStatus.BookedByParticipant, dt);

                        GetData.WriteLog(this.Name, GetData.GetInitiatorName(Convert.ToInt32(dTable.Rows[i][1])), "book request", "book", "phase_3", "booked " + resType + " " + resName + " " + requestedResourceQuantity);
                    }
                    // Else if no resources
                    else
                    {
                        // Update messege status with 0
                        UpdateMessageStatus(Convert.ToInt32(dTable.Rows[i][5]), MessageStatus.RefusedByParticipant);
                        //BookResource(res_name, res_type, currentResourceQuantity, deadlineTime);
                        GetData.WriteLog(this.Name, GetData.GetInitiatorName(Convert.ToInt32(dTable.Rows[i][1])), "refuse request", "not enough resource", "phase_3", "not enough " + resType + " " + resName + " " + requestedResourceQuantity);
                    }
                }

                    // Checks whether there is any booked resource is timeout
                else if (Convert.ToInt32(dTable.Rows[i][4]) == MessageStatus.BookedByParticipant)
                {
                    // if current time >= deadlineTime
                    // if dedline is over
                    int deadLine = Convert.ToInt32(dTable.Rows[i][8]);
                    //DateTime currTime = DateTime.Now;
                    if (!GetData.IsValidDeadline(deadLine))
                    {
                        //Update the resource quantity
                        UpdateResourceQuantity(resName, resType, requestedResourceQuantity, resStart, resEnd);
                        //      Cancel by Participant
                        GetData.UpdateMessageStatus(Convert.ToInt32(dTable.Rows[i][5]), MessageStatus.RefusedByParticipant);
                        GetData.WriteLog(this.Name, GetData.GetInitiatorName(Convert.ToInt32(dTable.Rows[i][1])), "refuse booking", "timeout", "phase_3", "booking rufused for timeout " + resType + " " + resName + " " + requestedResourceQuantity);
                    }
                }

                    //if initiator cancelled booking
                else if (Convert.ToInt32(dTable.Rows[i][4]) == MessageStatus.RefusedByInitiator)
                {
                    // Update the resource
                    // Make the msg obsolute status = 100
                    UpdateResourceQuantity(resName, resType, requestedResourceQuantity, resStart, resEnd);
                    UpdateMessageStatus(Convert.ToInt32(dTable.Rows[i][5]), MessageStatus.TrashMessage);
                }
                //if initiator make a contract
                else if (Convert.ToInt32(dTable.Rows[i][4]) == MessageStatus.AgreedByInitiator)
                {
                    UpdateMessageStatus(Convert.ToInt32(dTable.Rows[i][5]), MessageStatus.AgreedByParticipant);
                    //GetData.WriteLog(this.Name, GetData.GetInitiatorName(Convert.ToInt32(dTable.Rows[i][1])), "task", "agree", "phase_4", "agree for " + resType + " " + resName + " " + requestedResourceQuantity);

                    InfoBoard.IncrementNoTbyParticipant(Name);
                    GetData.WriteLog(this.Name, "Information Board", "Update", "NoT", "phase_4", this.Name + "updates NoT to IB");
                    int currentduration = GetData.GetResourceDurationFromParticipant(GetData.GetParticipantId(this.Name), dTable.Rows[i][2].ToString(),
                                                                                     dTable.Rows[i][7].ToString());
                    while (currentduration != 0)
                    {
                        currentduration--;
                    }

                    UpdateMessageStatus(Convert.ToInt32(dTable.Rows[i][5]), MessageStatus.FinishTaskByParticipant);
                    GetData.WriteLog(this.Name, GetData.GetInitiatorName(Convert.ToInt32(dTable.Rows[i][1])), "task", "finish", "phase_6", "finish task for " + resType + " " + resName + " " + requestedResourceQuantity);
                }
                //if initiator checked the finish task
                else if (Convert.ToInt32(dTable.Rows[i][4]) == MessageStatus.CheckedFinishTaskByInitiator)
                {
                    UpdateMessageStatus(Convert.ToInt32(dTable.Rows[i][5]), MessageStatus.SuccessfulyFinished);
                    //GetData.WriteLog(this.Name, GetData.GetInitiatorName(Convert.ToInt32(dTable.Rows[i][1])), "task", "successful", "phase_6", "successfully done for " + resType + " " + resName + " " + requestedResourceQuantity);

                    InfoBoard.IncrementNoFTbyParticipant(Name);
                    GetData.WriteLog(this.Name, "Information Board", "Update", "NoFT", "phase_6", this.Name + "updates NoFT to IB");

                    // if only resource type is transportation
                    //if (resType == "Transport")
                    //    UpdateResourceQuantity(resName, resType, requestedResourceQuantity, resStart, resEnd);
                }
                else
                    Console.WriteLine("Wrong!");
            }
        }

        private void BookResource(string resName, string resType, int requestedResourceQuantity, string resStart, string resEnd)
        {
            GetData.UpdateResourceQuantity(resName, resType, -requestedResourceQuantity, resStart, resEnd, Name);
        }

        private void UpdateResourceQuantity(string resName, string resType, int requestedResourceQuantity, string resStart, string resEnd)
        {
            GetData.UpdateResourceQuantity(resName, resType, requestedResourceQuantity, resStart, resEnd, Name);
        }

        private int GetCurrentQuantityOfResource(string resName, string resType, string resStart, string resEnd)
        {
            int resQuan = GetData.GetCurrentQuantityOfResource(resName, resType, resStart, resEnd, Name);

            return resQuan;
        }

        private bool UpdateMessageStatus(int msgId, int msgStatus)
        {
            GetData.UpdateMessageStatus(msgId, msgStatus);

            return true;
        }

        private bool UpdateMessageStatus(int msgId, int msgStatus, int dt)
        {
            GetData.UpdateMessageStatus(msgId, msgStatus, dt);

            return true;
        }

        // if there is new messege
        // notify the IB
        // check if enough resources
        //  yes: book resources and notify the initiator and notify IB
        //  book resources: save init info and amount and status as booked
        //                  reduce no of available resources
        //  no: notify the initiator.
    }
}